const http = require('http');
const url = require('url');
const path = require('path');
const util = require('./util');
const fs = require('fs').promises
const chalk = require('chalk');
const mime = require('mime');
const { createReadStream, readFileSync } = require('fs');
// ejs解析模板
const ejs = require('ejs');
const template = readFileSync(path.resolve(__dirname, 'template.html'), 'utf8');
class Server {
    constructor(serverOptions) {
        this.port = serverOptions.port;
        this.directory = serverOptions.directory;
        this.cache = serverOptions.cache;
        this.gzip = serverOptions.gzip
        this.handleRequest = this.handleRequest.bind(this);
        this.template = template;
    }
    async handleRequest(req, res) {
        // 1. 解析路径  =>  /src
        let { pathname } = url.parse(req.url);
        // 2. 文件命名是中文，解析会出问题，需要decode一下
        pathname = decodeURIComponent(pathname)
        // 3. 完整路径，用户不传directory，则默认cwd()的目录
        // C:\Users\Desktop\http-server\http-server\src
        let requestFile = path.join(this.directory, pathname);

        try {
            let statObj = await fs.stat(requestFile);
            // 如果是文件夹
            if (statObj.isDirectory()) {
                // 读取文件夹下的文件
                // [ 'index.js', 'template.html', 'util.js' ]
                const dirs = await fs.readdir(requestFile);

                // 根据数据和模板渲染内容
                let fileContent = await ejs.render(this.template, {
                    dirs: dirs.map((dir) => ({
                        name: dir,
                        url: path.join(pathname, dir)
                    }))
                });

                res.setHeader('Content-Type', 'text/html;charset=utf-8');
                
                // 将模板替换后的文件内容，返回给浏览器进行渲染
                res.end(fileContent);
            // 如果是文件，则发送文件
            } else {
                this.sendFile(req, res, requestFile)
            }
        } catch (e) {
            console.log(e)
            this.sendError(req, res, e);
        }
    }
    // 根据路径边读编写，输出给浏览器解析
    sendFile(req, res, requestFile) {
        // 返回文件，需要给浏览器提供内容类型 和 内容的编码格式，浏览器才能识别出来去解析
        res.setHeader('Content-Type', mime.getType(requestFile) + ';charset=utf-8');
        // 将文件读取出来并且返回
        // 如果不结束，浏览器相当于没有接受完毕
        createReadStream(requestFile).pipe(res); // 流. ws.write() ws.write() ws.end()
    }
    // 访问文件地址不存在
    sendError(req, res, e) {
        res.statusCode = 404;
        res.end(`Not Found`)
    }
    start() {
        // 启动服务监听错误信息，如果端口占用 累加1
        const server = http.createServer(this.handleRequest);
        server.listen(this.port, () => { // 订阅方法 监听成功后会触发
            console.log(chalk.yellow('Starting up http-server, serving ./'))
            console.log(chalk.yellow('Available on:'));
            console.log(`http://` + util.getIp().address + `:${chalk.green(this.port)}`);
            console.log(`http://127.0.0.1:${chalk.green(this.port)}`);
        });

        // 如果报错是EADDRINUSE，端口占用，则+1监听新端口
        server.on('error', (err) => {
            if (err.errno === 'EADDRINUSE') {
                server.listen(++this.port)
            }
        })
    }
}


module.exports = Server